<?php

// 认证码类

class Vcode {

    private $img;           //图片对象
    private $imw = 160;     //宽
    private $imh = 40;      //高
    private $type = '';     // emtel, vsms4, 
    private $mod = '';      //模块
    private $code = '';     //字符
    private $ttid = -1;

    static $ctabN = [];
    static $ctabA = [];
    static $ctabB = [];

    # 颜色表
    static function initTab(){
        self::$ctabN['4'] = ['0'=>0,  '5'=>85,  'A'=>170,  'F'=>255];                       # gap:5 : 0-5-A-F
        self::$ctabN['5'] = ['00'=>0, '40'=>64, '80'=>128, 'C0'=>192, 'F0'=>255];           # gap:8 : 00:80:C0:F0 
        self::$ctabN['6'] = ['0'=>0,  '3'=>51,  '6'=>102,  '9'=>153,  'C'=>204,  'F'=>255]; # gap:6
        self::$ctabA['6'] = [
            '0'=>['6','9','C','F'],
            '3'=>[    '9','C','F'],
            '6'=>['0',    'C','F'],
            '9'=>['0','3',    'F'],
            'C'=>['0','3','6'    ],
            'F'=>['0','3','6','9'],
        ];
        self::$ctabB['6'] = [
            '0'=>[    '3'],
            '3'=>['0','6'],
            '6'=>['3','9'],
            '9'=>['6','C'],
            'C'=>['9','F'],
            'F'=>['C'    ],
        ];
    }

    private $ctbs = [];

    # 前背景颜色
    static function tabrc($n=6, $rc3=0, $rx=0){
        self::initTab();
        $tbcn = self::$ctabN['6']; $tbkn = array_keys($tbcn); 
        $tban = self::$ctabA['6']; $tbbn = self::$ctabB['6'];
        # one
        if(!$n){
            return $rc3 ? implode('',$tb3) : [$tbcn[$tb3[0]],$tbcn[$tb3[1]],$tbcn[$tb3[2]]];
        }
        # RGB(n+1)
        $tb3 = $ts1 = []; shuffle($tbkn); #dump($tbkn);
        $xb3 = $xs1 = [];
        for($i=0;$i<3;$i++){
            $tb3[] = $k1 = $tbkn[$i]; $ts1[] = $tban[$k1];
            $xb3[] = $k1 = $tbkn[$i]; $xs1[] = $tbbn[$k1];
        } #dump($tb3); dump($ts1);
        # return n + 1 
        $ts3[] = $rc3 ? implode('',$tb3) : [$tbcn[$tb3[0]],$tbcn[$tb3[1]],$tbcn[$tb3[2]]];
        for($i=0;$i<$n;$i++){ 
            $k1 = array_rand($ts1[0],1); $c1=$ts1[0][$k1]; $k2 = array_rand($ts1[1],1); $c2=$ts1[1][$k2]; $k3 = array_rand($ts1[2],1); $c3=$ts1[2][$k3];
            $ts3[] = $rc3 ? "$c1$c2$c3" : [$tbcn[$c1],$tbcn[$c2],$tbcn[$c3]];
            $k1 = array_rand($xs1[0],1); $c1=$xs1[0][$k1]; $k2 = array_rand($xs1[1],1); $c2=$xs1[1][$k2]; $k3 = array_rand($xs1[2],1); $c3=$xs1[2][$k3];
            $xs3[] = $rc3 ? "$c1$c2$c3" : [$tbcn[$c1],$tbcn[$c2],$tbcn[$c3]];
        }
        #dump($tb3); dump($ts1); dump($ts3); 
        return [$ts3, $xs3];
    }

    function __construct($type='', $mod='(istest)', $code='0'){ 
        // 显示图片一般图片
        if(function_exists('imagecreate')){ 
            $this->init($type, $mod, $code);
            $this->show();
        }else{ //bmp
            abort('Function `imagecreate` NOT Found.', 611); 
        }
    }
    function init($type, $mod, $code='0'){
        $this->type = $type; 
        $this->mod = $mod; 
        $this->code = $code ?: ($type=='vsms4' ? self::strRand(4,'0') : self::strRand());
        $_SESSION["vcode_$mod"] = $this->code; // save ??? 
        if($this->type=='emtel'){ $this->imw = 20+strlen($this->code)*20; }
        $this->img = imagecreate($this->imw, $this->imh); 
        // 填充
        $this->ctbs = $this->tabrc(strlen($this->code), 0, 1); # n+1个颜色
        $bgColor = $this->rndCimg($this->ctbs[0][0]);
        imagefill($this->img, 0, 0, $bgColor);
    }

    // 显示
    function show(){
        //$this->_rndPixels(); // ...
        $this->drawStr();
        //$this->distOrtion();
        // output
        $typa = array(1=>'gif', 2=>'png', 3=>'jpeg'); 
        $type = $typa[rand(1,3)]; 
        ob_clean();
        header("Content-type:image/$type");
        $func = "image$type"; //imagejpeg
        $func($this->img); 
        imagedestroy($this->img); 
    }
    // Draw字符
    function drawStr(){        
        for($i=0;$i<strlen($this->code);$i++) {
            $chr = $this->code[$i];
            if($this->type=='emtel'){
                $size = 20;
            }else{
                $size = mt_rand(16,20); 
            }
            $angle = $this->type=='emtel' ? 0              : mt_rand(-15,15);
            $x     = $this->type=='emtel' ? $i*20+8        : mt_rand(15,20)+$i*26;
            $y     = $this->type=='emtel' ? mt_rand(24,30) : mt_rand(27,30);
            $ffile = $this->rndFonts($chr); $tcolor = $this->rndCimg($this->ctbs[0][$i+1]);
            if($this->type!='emtel'){
                // 外围描边(空心效果) ctab -> ctbs
                $cb = $this->rndCimg($this->ctbs[1][$i]); 
                imagettftext($this->img, $size, $angle, $x+1, $y, $cb, $ffile, $chr); // x
                imagettftext($this->img, $size, $angle, $x, $y+1, $cb, $ffile, $chr); // y
            }
            // 文字本身
            imagettftext($this->img, $size, $angle, $x, $y, $tcolor, $ffile, $chr);
        }
    }
    // 随机颜色
    function rndCimg($ctab){
        $cl = imagecolorallocate($this->img, $ctab[0], $ctab[1], $ctab[2]);
        if($cl===false){
            $cl = imagecolorclosest($this->img, $ctab[0], $ctab[1], $ctab[2]);
        } 
        return $cl;
    }

    // 随机颜色
    function rndColor($no=0){
        $ct = [];
        for($i=0;$i<3;$i++){ $ct[]=mt_rand(2,254); }
        $cl = $this->rndCimg($ct); 
        return $cl;
    }
    // 随机Font
    function rndFonts($chr=''){
        $fonts = ['wch-avant', 'wch-bvsans', 'wch-miriam']; // 均衡, 较粗, 细小
        if($this->ttid<0){ $this->ttid = $ttid = mt_rand(0,count($fonts)-1); }
        else{ $ttid = $this->ttid+1; if($ttid>=count($fonts)){ $ttid=0; } } // 下一个
        if(!$ttid && $chr=='@'){ $ttid=1; } // ttid=0:不显示特殊字符
        $this->ttid = $ttid; 
        return DIR_STATIC.'/ui3nd/fonts/'.$fonts[$ttid].'.ttf'; 
    }

    // 随机码
    static function strRand($rn=0, $key='K'){
        if(!$rn){ $rn = mt_rand(3,5); }
        return Basic::kidRand($key, $rn);
    }

}

/*
    /home-vcode?type=vsms4
    /home-vcode
    /?r=home-vcode&type=emtel&code=135-37432147
*/
